package com.uptown.nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * @author: Lixiaofei
 * @date: 2020/5/15 15:26
 */
public class GroupChatServer {

    private Selector selector;

    private ServerSocketChannel listenChannel;

    private static final int port = 6667;

    public GroupChatServer() {
        try {
            selector = Selector.open();
            listenChannel = ServerSocketChannel.open();
            listenChannel.socket().bind(new InetSocketAddress(port));
            //设置非阻塞模式
            listenChannel.configureBlocking(false);
            //将listenChannel注册到selector上  监听连接事件
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void listen(){
        try{
            //循环监听
            while (true){
                int count = selector.select();
                if(count>0){
                    //有事件处理
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()){
                        //取出selectionkey
                        SelectionKey next = iterator.next();
                        //监听到连接事件
                        if(next.isAcceptable()){
                            SocketChannel sc = listenChannel.accept();
                            sc.configureBlocking(false);
                            //注册到selector   监听读操作
                            sc.register(selector,SelectionKey.OP_READ);
                            sc.configureBlocking(false);
                            System.out.println(sc.getRemoteAddress()+"上线");
                        }
                        if(next.isReadable()){ //通道发生read事件，通道是可读状态
                            readData(next);
                        }
                       //防止重复处理  去除
                        iterator.remove();
                    }
                }else{
                    System.out.println("等待连接....");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {

        }
    }

    //读取客户端消息
    private void readData(SelectionKey selectionKey){
        //定义一个ScoketChannel
        SocketChannel socketChannel = null;
        try{
            //取到关联得channel
            socketChannel = (SocketChannel)selectionKey.channel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            int count = socketChannel.read(byteBuffer);
            if(count > 0){
                String str = new String(byteBuffer.array());
                System.out.println("from 客户端"+new String(byteBuffer.array()));
                //向其他客户端转发消息
                sendInfoToOtherClients(str,socketChannel);
            }
        }catch (IOException e){
            //服务端调用读取客户端信息时如果出现异常则判定为离线
            try {
                System.out.println(socketChannel.getRemoteAddress()+"离线了");
                selectionKey.cancel();
                //关闭通道
                socketChannel.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    //转发消息给其他客户端
    private void sendInfoToOtherClients(String msg,SocketChannel self) throws IOException {
        System.out.println("服务器转发消息中。。。。");
        //遍历所有注册到selector上的scoketChannel并排除自己
        for(SelectionKey key : selector.keys()){
            //取出通道
            Channel targetChannel = key.channel();
            //排除注册的ServerScoketChannel
            if(targetChannel instanceof SocketChannel && targetChannel!=self){
                //转成SocketChannel
                SocketChannel socketChannel = (SocketChannel) targetChannel;
                ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes());
                socketChannel.write(wrap);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        //创建一个服务器对象
        GroupChatServer groupChatServer = new GroupChatServer();
        groupChatServer.listen();

    }

}
